////////////////////////////////////////////////////////////////////////////////
// Copyright 2006 CORE Solutions Limited
// All rights reserved.
// PROPRIETARY AND CONFIDENTIAL INFORMATION.
// Use is subject to license terms.
//
// FUNCTION ID      :   
// AUTHOR           :    
// DATE CREATE      :   
// DESCRIPTION      :   
//                  :   
//                  :   
//                  :   
//
// MODIFICATION HISTORY:
// DATE         AUTHOR          VERSION NO.         COMMENT
// -----------  --------------  ------------------  -------------------
// 2006/05/11   Ric Yik         1.0                 BugZilla #5534
// 2006/05/11   Ric Yik         1.0                 BugZilla #5768
// 2006/05/17   Ric Yik         1.0                 BugZilla #5796
//
////////////////////////////////////////////////////////////////////////////////
package com.erp.framework.controller.action;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.struts.action.ActionError;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;

import com.erp.app.admin.sysParam.beans.SysParamList;
import com.erp.app.common.ProjectConstants;
import com.erp.app.util.web.WebUtil;
import com.erp.framework.SimpleConstants;
import com.erp.framework.controller.form.MultiRow;
import com.erp.framework.controller.form.SimplePageEditStyleForm;
import com.erp.framework.exceptions.CheckFieldLengthException;
import com.erp.framework.exceptions.FindRecordException;
import com.erp.framework.model.criteria.SimpleBaseSrchCriteria;
import com.erp.framework.model.delegate.SimplePageEditStyleDelegate;
import com.erp.framework.model.pk.SimpleBasePk;
import com.erp.framework.model.pk.SimplePageEditStylePk;
import com.erp.framework.model.schema.TableSchema;
import com.erp.framework.model.vo.ChildList;
import com.erp.framework.model.vo.SimpleBaseVo;
import com.erp.framework.model.vo.SimplePageEditStyleVo;
import com.erp.framework.util.BeanUtil;
import com.erp.framework.util.CommonUtil;
import com.erp.framework.util.CopyUtil;
import com.erp.framework.util.logger.Logger;
import com.erp.framework.util.user.User;

//ERP: not used anymore
//import com.erp.object.common.beans.MasterDelegateInterface;

public abstract class SimplePageEditStyleAction extends SimpleCoreAction {

    // //////////////////////////////////////////////////////////////////////////////
    // ABSTRACT METHODS THAT NEED BE IMPLEMENTED BY SUB-CLASSES
    // //////////////////////////////////////////////////////////////////////////////

    protected abstract String getModuleName(ActionMapping mapping, ActionForm formIn, HttpServletRequest request,
            HttpServletResponse response);

    protected abstract String getFunctionId();

    protected abstract void setFormType(ActionMapping mapping, ActionForm formIn, HttpServletRequest request,
            HttpServletResponse response, ActionErrors errors);

    protected abstract String getMasterDelegateName();

    protected abstract Class getMasterFormClass();

    protected abstract Class getMasterVOClass();

    protected abstract Class getDetailVOClass();

    protected abstract Class getDetailFormClass();

    protected abstract String getDetailFormSessionName();

    protected abstract Class getSearchCriteriaClass();

    protected abstract void setOtherCriteria(ActionMapping mapping, ActionForm formIn, HttpServletRequest request,
            HttpServletResponse response, ActionErrors errors, Object criteria);

    // //////////////////////////////////////////////////////////////////////////////
    // END OF ABSTRACT METHODS
    // //////////////////////////////////////////////////////////////////////////////

    // //////////////////////////////////////////////////////////////////////////////
    // OPTIONAL METHODS THAT CAN BE OVERWRITTEN BY SUB-CLASSES
    // //////////////////////////////////////////////////////////////////////////////

    // the following method is only to be overwritten by sub-class if intended
    // to set the aut-search on-load to on/off
    protected boolean getLoadOnEnter() {

        return true;
    }

    // the following method is only to be overwritten by sub-class if intended
    // to set the clearing search result sets on-load to on/off
    protected boolean getResetOnEnter() {

        return false;
    }

    protected void initAction(ActionMapping mapping, ActionForm formIn, HttpServletRequest request, HttpServletResponse response,
            ActionErrors errors) {
    	
    }

    // old way
    /**
     * @ddeprecated
     */
    protected void initAction(ActionMapping mapping, ActionForm formIn, HttpServletRequest request, HttpServletResponse response) {
    }

    protected void initForm(ActionMapping mapping, ActionForm formIn, HttpServletRequest request, HttpServletResponse response,
            ActionErrors errors) {

        SimplePageEditStyleForm form = (SimplePageEditStyleForm) formIn;
        ActionForward actionForward = new ActionForward(mapping.getInput());

        if (getResetOnEnter()) {
            form.resetForm();
        }
    }

    protected void initPage(ActionMapping mapping, ActionForm formIn, HttpServletRequest request, HttpServletResponse response,
            ActionErrors errors) {

    }

    // old way
    /**
     * @ddeprecated
     */
    protected void initPage(ActionMapping mapping, ActionForm formIn, HttpServletRequest request, HttpServletResponse response) {

    }

    protected void afterSearch(ActionMapping mapping, ActionForm formIn, HttpServletRequest request,
            HttpServletResponse response, ActionErrors errors) {

    }

    protected void beforeSearch(ActionMapping mapping, ActionForm formIn, HttpServletRequest request,
            HttpServletResponse response, ActionErrors errors) {

    }

    protected void afterSave(ActionMapping mapping, ActionForm formIn, HttpServletRequest request, HttpServletResponse response,
            ActionErrors errors) {

    }

    protected void beforeSave(ActionMapping mapping, ActionForm formIn, HttpServletRequest request, HttpServletResponse response,
            ActionErrors errors) {

    }

    protected void beforeRefresh(ActionMapping mapping, ActionForm formIn, HttpServletRequest request,
            HttpServletResponse response, ActionErrors errors) {

    }

    protected void afterRefresh(ActionMapping mapping, ActionForm formIn, HttpServletRequest request,
            HttpServletResponse response, ActionErrors errors) {

    }

    // new way
    protected void beforeAddRow(ActionMapping mapping, ActionForm formIn, HttpServletRequest request,
            HttpServletResponse response, ActionErrors errors) {

        // handle the old way
        beforeAdd(mapping, formIn, request, response);
    }

    // new way
    protected void afterAddRow(ActionMapping mapping, ActionForm formIn, HttpServletRequest request,
            HttpServletResponse response, ActionErrors errors) {

        // handle the old way
        afterAdd(mapping, formIn, request, response);
    }

    protected void beforeDeleteRow(ActionMapping mapping, ActionForm formIn, HttpServletRequest request,
            HttpServletResponse response, ActionErrors errors) {

    }

    protected void afterDeleteRow(ActionMapping mapping, ActionForm formIn, HttpServletRequest request,
            HttpServletResponse response, ActionErrors errors) {

    }

    // old way
    /**
     * @ddeprecated
     */
    protected void beforeAdd(ActionMapping mapping, ActionForm formIn, HttpServletRequest request, HttpServletResponse response) {

    }

    // old way
    /**
     * @ddeprecated
     */
    protected void afterAdd(ActionMapping mapping, ActionForm formIn, HttpServletRequest request, HttpServletResponse response) {

    }

    protected void beforeVosToForm(ActionMapping mapping, ActionForm formIn, HttpServletRequest request,
            HttpServletResponse response, ActionErrors errors, Collection collection) {

    }

    protected void afterVosToForm(ActionMapping mapping, ActionForm formIn, HttpServletRequest request,
            HttpServletResponse response, ActionErrors errors, Collection collection) {

    }

    protected void beforeFormToVos(ActionMapping mapping, ActionForm formIn, HttpServletRequest request,
            HttpServletResponse response, ActionErrors errors, Collection collection) {

    }

    protected void afterFormToVos(ActionMapping mapping, ActionForm formIn, HttpServletRequest request,
            HttpServletResponse response, ActionErrors errors, Collection collection) {

    }

    // old way
    /**
     * @ddeprecated
     */
    protected void validateInput(ActionErrors errors, SimpleBaseVo bizModel) throws Exception {
    }

    // old way
    /**
     * @ddeprecated
     */
    protected void filterForEmptyInput(SimpleBaseVo current) throws Exception {
    }

    // the following method is only to be overwritten by sub-class if intended
    // to use a new delegate class instead
    protected Class getMasterDelegateClass() {

        return SimplePageEditStyleDelegate.class;
    }

    // protected String getMasterDelegateName() {
    //        
    // return "MASTER_DELEGATE";
    // }

    // the following method is only to be overwritten by sub-class if intended
    // to use a session name for the status
    protected String getSessionSimpleMastersStatus() {

        return SimpleConstants.SESSION_SIMPLE_MASTERS_STATUS;
    }

    protected void setSessionFields(HttpServletRequest request, SimpleBaseVo bizModel) {

    }

    protected SimpleBaseVo getInitialzedModel(ActionForm form, User editingUser) {

        return null;
    }

    // //////////////////////////////////////////////////////////////////////////////
    // END OF OPTIONAL METHODS
    // //////////////////////////////////////////////////////////////////////////////

    // //////////////////////////////////////////////////////////////////////////////
    // LOGICAL AND BUSINESS METHODS
    // //////////////////////////////////////////////////////////////////////////////

    protected ActionForward handlePageEvent(ActionMapping mapping, ActionForm formIn, HttpServletRequest request,
            HttpServletResponse response, ActionErrors errors) {

        return (new ActionForward(mapping.getInput()));
    }

    protected ActionForward processOtherStatus(ActionMapping mapping, ActionForm formIn, HttpServletRequest request,
            HttpServletResponse response, ActionErrors errors, String rb_status) {

        ActionForward actionForward = new ActionForward(mapping.getInput());

        return actionForward;
    }

    protected ActionForward otherExecute(ActionMapping mapping, ActionForm formIn, HttpServletRequest request,
            HttpServletResponse response) throws ServletException {

        ActionForward actionForward = null;
        try {
            HttpSession session = request.getSession(false);
            ActionErrors errors = new CustomActionErrors(new ActionErrors());

            // old way
            initAction(mapping, formIn, request, response);
            // new way
            initAction(mapping, formIn, request, response, errors);

            SimplePageEditStyleForm form = (SimplePageEditStyleForm) formIn;
            String action = form.getPageEvent();
            action = CommonUtil.isEmpty(action) ? "" : action.trim();
            actionForward = new ActionForward(mapping.getInput());
            String rb_status = CommonUtil.nullToString((String) session.getAttribute(getSessionSimpleMastersStatus()));
            session.removeAttribute(getSessionSimpleMastersStatus());

            User editingUser = (User) session.getAttribute(SimpleConstants.SESSION_USER);

            Logger.debug(this, "otherExecute(), action = " + action + ", status=[" + rb_status + "]");
            Logger.debug(this, "otherExecute(), !isHandled(request)=[" + isHandled(request) + "]");

            form.setMultiRowClazz(getDetailFormClass());
            populateIsDelete(formIn, request);
            form.getFinalRows();

            setFormType(mapping, form, request, response, errors);
                
            if (!isHandled(request) && !rb_status.equals("")) {
                actionForward = processStatus(mapping, formIn, request, response, errors, rb_status);
            }

            // for initial status
            if (!isHandled(request) && action.length() == 0) {
                initForm(mapping, formIn, request, response, errors);
                
                if (getLoadOnEnter()) {
                    resetHandled(request);
                    action = ACTION_SEARCH;
                } else {
                    setHandled(request);
                    // ERP: not used anymore
                    // removeMasterDelegateInterface(session);
                    removeMasterDelegate(session);

                    SimplePageEditStyleForm tmpForm = (SimplePageEditStyleForm) formIn;
                    form = (SimplePageEditStyleForm) getMasterFormClass().newInstance();
                    form.setMenuObjectList(tmpForm.getMenuObjectList());
                    initPage(mapping, form, request, response, errors); // new way
                    initPage(mapping, form, request, response); // old way
                    session.setAttribute(getDetailFormSessionName(), form);
                }
            }

            try{
            // Sets the TableSchema
                super.copyTsFromVoToForm(mapping, form, request, response, null); 
                session.setAttribute(getDetailFormSessionName(), form);
            } catch(Exception e){
                Logger.logExceptions(this, e);
            }
                
            // action: Search
            if (!isHandled(request) && action.equalsIgnoreCase(ACTION_SEARCH)) {
                processActionSearch(mapping, form, request, response, errors);
                setHandled(request);
            }

            // action: add a row
            else if (!isHandled(request) && action.equalsIgnoreCase(ACTION_ADD_ROW)) {
                beforeAddRow(mapping, form, request, response, errors);
                if (form.isMultiPage()) {
                    // scroll to last page if rows is added
                    if (!form.getHasAddedRows()) {
                        form.setSidx(form.getMultiRows().size() - 1);
                        form.setHasAddedRows(true);
                    }
                }

                SimpleBaseVo model = getInitialzedModel(form, editingUser);
                if (model != null) {
                    form.addRow(model);
                } else {
                    form.addRow();
                }

                setHandled(request);
                afterAddRow(mapping, form, request, response, errors);

            } else if (!isHandled(request) && action.equalsIgnoreCase(ACTION_ADD_MULTI_ROW)) {
                // beforeAddRow(mapping, form, request, response, errors);
                if (form.isMultiPage()) {
                    // scroll to last page if rows is added
                    if (!form.getHasAddedRows()) {
                        form.setSidx(form.getMultiRows().size() - 1);
                        form.setHasAddedRows(true);
                    }
                }

                SimpleBaseVo model = getInitialzedModel(form, editingUser);
                if (model != null) {
                    // form.addRow(model);
                } else {
                    // form.addRow();
                }

                setHandled(request);
                // afterAddRow(mapping, form, request, response, errors);
            }

            else if (!isHandled(request) && action.equals(ACTION_DELETE_ROW)) {
                beforeDeleteRow(mapping, form, request, response, errors);
                int pageEventSrc = Integer.parseInt(form.getPageEventSrc());

                MultiRow row = (MultiRow) form.getMultiRows(0).get(pageEventSrc);
                row.setIsDelete(GENERIC_YES);
                afterDeleteRow(mapping, form, request, response, errors);
            }

            else if (!isHandled(request) && action.equals(ACTION_PURGE_ROW)) {
                beforeDeleteRow(mapping, form, request, response, errors);
                int pageEventSrc = Integer.parseInt(form.getPageEventSrc());

                MultiRow row = (MultiRow) form.getMultiRows(0).get(pageEventSrc);
                row.setIsDelete(GENERIC_YES);
                row.setDeleteForever(true);
                afterDeleteRow(mapping, form, request, response, errors);
            } else if (!isHandled(request) && action.equalsIgnoreCase(ACTION_SCROLL_LEFT)) {
                setHandled(request);
                actionForward = processActionScrollLeft(mapping, formIn, request, response, errors);
                saveToken(request);
            } else if (!isHandled(request) && action.equalsIgnoreCase(ACTION_SCROLL_RIGHT)) {
                setHandled(request);
                actionForward = processActionScrollRight(mapping, formIn, request, response, errors);
                saveToken(request);
            } else if (!isHandled(request) && action.equalsIgnoreCase(ACTION_SCROLL_TO_FIRST_PAGE)) {
                setHandled(request);
                actionForward = processActionScrollToFirstPage(mapping, formIn, request, response, errors);
                saveToken(request);
            } else if (!isHandled(request) && action.equalsIgnoreCase(ACTION_SCROLL_TO_LAST_PAGE)) {
                setHandled(request);
                actionForward = processActionScrollToLastPage(mapping, formIn, request, response, errors);
                saveToken(request);
            }  else if (!isHandled(request) && action.equalsIgnoreCase(ACTION_SCROLL_TO)) {
                setHandled(request);
                actionForward = processActionScrollTo(mapping, formIn, request, response, errors);
                saveToken(request);
            }
//            else if (!isHandled(request) && action.indexOf(ACTION_SCROLL) != -1) {
//                int sidx = form.getSidx();
//
//                if (action.equalsIgnoreCase("scrollLeft"))
//                    sidx -= SimpleConstants.MAX_DISPLAY;
//                else
//                    sidx += SimpleConstants.MAX_DISPLAY;
//
//                if (sidx < 0)
//                    sidx = 0;
//                if (sidx > form.getMultiRows().size() - 1)
//                    sidx = form.getMultiRows().size() - 1;
//
//                form.setSidx(sidx);
//
//                form.getFinalRows();
//
//                setHandled(request);
//            }
            // action: save the list
            else if (!isHandled(request) && action.equalsIgnoreCase(ACTION_SAVE)) {
                setHandled(request);
                actionForward = processActionSave(mapping, formIn, request, response, errors);
            }

            // action: cancel
            else if (!isHandled(request) && action.equalsIgnoreCase(ACTION_CANCEL)) {                
                setHandled(request);
                actionForward = processActionCancel(mapping, formIn, request, response, errors);
            }

            // action: exit
            else if (!isHandled(request) && action.equalsIgnoreCase(ACTION_EXIT)) {
                session.removeAttribute(getDetailFormSessionName());
                // ERP: not use anymore
                // removeMasterDelegateInterface(session);
                removeMasterDelegate(session);
                actionForward = mapping.findForward("default");
                setHandled(request);
            }

            else if (!isHandled(request) && action.equalsIgnoreCase(ACTION_CLEAR)) {
                actionForward = processActionClear(mapping, formIn, request, response, errors);

            }

            // added
            // action: refresh
            else if (!isHandled(request) && action.equalsIgnoreCase(ACTION_REFRESH)) {
                actionForward = processActionRefresh(mapping, formIn, request, response, errors);
            }

            // action: other actions
            else if (!isHandled(request) && !CommonUtil.isEmpty(action)) {
                actionForward = handlePageEvent(mapping, formIn, request, response, errors);
                setHandled(request);
            }

            form.setMode("modify");

            saveErrors(request, errors);
            saveToken(request);
        } catch (Exception e) {
            Logger.logExceptions(this, e);
        }
        return actionForward;
    }

    protected ActionForward processStatus(ActionMapping mapping, ActionForm formIn, HttpServletRequest request,
            HttpServletResponse response, ActionErrors errors, String rb_status) {
        ActionForward actionForward = new ActionForward(mapping.getInput());
        
        setHandled(request);
        return processOtherStatus(mapping, formIn, request, response, errors, rb_status);            
    }

    
    protected Object setCriteria(ActionMapping mapping, ActionForm formIn, HttpServletRequest request,
            HttpServletResponse response, ActionErrors errors) {

        Object criteria = null;
        try {
            SimplePageEditStyleForm form = (SimplePageEditStyleForm) formIn;
            criteria = getSearchCriteriaClass().newInstance();
            CopyUtil.cpNconv(criteria, form);
            HttpSession session = request.getSession(false);
            User editingUser = (User) session.getAttribute(SimpleConstants.SESSION_USER);
            SysParamList list = (SysParamList) session.getAttribute(ProjectConstants.SESSION_SYS_PARAM);
            ((SimpleBaseSrchCriteria) criteria).setSysParamList(list);
            ((SimpleBaseSrchCriteria) criteria).setLoginCompanyCode(WebUtil.getAppropriateCompanyCode(session, null));
            ((SimpleBaseSrchCriteria) criteria).setSrchUser(editingUser);
            setOtherCriteria(mapping, formIn, request, response, errors, criteria);
        } catch (Exception e) {
            Logger.logExceptions(this, e);
        }

        return criteria;
    }

    protected void processActionSearch(ActionMapping mapping, ActionForm formIn, HttpServletRequest request,
            HttpServletResponse response, ActionErrors errors) {

        try {
            HttpSession session = request.getSession(false);
            SimplePageEditStyleForm form = (SimplePageEditStyleForm) formIn;
            // 1. remove old MastersDelegate from session

            beforeSearch(mapping, formIn, request, response, errors);
            form.validateSearch(errors);
            form.moreValidateSearch(mapping, formIn, request, response, errors);

            // ERP: not used anymore
            // removeMasterDelegateInterface(session);
            removeMasterDelegate(session);

            // 2. create new MastersDelegate
            // ERP: not used anymore
            // MasterDelegateInterface dg = (MasterDelegateInterface) getMasterDelegateInterface(session);
            SimplePageEditStyleDelegate dg = getMasterDelegate(session);

            Object criteria = null;
            if (getSearchCriteriaClass() != null) {
                criteria = setCriteria(mapping, formIn, request, response, errors);
            }

            if (errors.size() != 0) {
                return;
            }

            String formType = form.getFormType();
            if (SimpleConstants.FORM_TYPE_PAGE_EDIT.equals(formType)) { // new way
                Collection collection = findByCriteria(dg, form, request, criteria);
                if (collection == null || collection.size() == 0) {
                    errors.add(ActionErrors.GLOBAL_ERROR, new ActionError("warning.no_record_found"));
                }
                form.getMultiRows().clear();
                form.reset(mapping, request);
                form.setHasAddedRows(false);
                form.setSidx(0);
                initPage(mapping, form, request, response, errors); // new way
                form.setOldValues(collection);
                beforeVosToForm(mapping, form, request, response, errors, collection);
                vosToForm(collection, form);
                afterVosToForm(mapping, form, request, response, errors, collection);

                //just get the first model for setting the table schema
                SimpleBaseVo bizModel = null;
                if((collection != null) && (collection.size() != 0)){
                    bizModel = (SimpleBaseVo)collection.toArray()[0];
                }
                super.copyTsFromVoToForm(mapping, form, request, response, bizModel);
                
                session.setAttribute(getDetailFormSessionName(), form);
                
            } else { // old way
                SimpleBaseVo bizModel = (SimpleBaseVo) searchByCriteria(dg, form, request, criteria);
                form.getMultiRows().clear();
                form.reset(mapping, request);
                form.setSidx(0);
                initPage(mapping, form, request, response); // old way
                form.setOldValues(bizModel);
                
                modelToForm(bizModel, form);
                
                //VICTOR, from ZH, generated code has no tableschema..., maybe missing in above if block.
                //must add to above if block and test
                super.copyTsFromVoToForm(mapping, form, request, response, bizModel);
                
                session.setAttribute(getDetailFormSessionName(), form);
            }
                

            afterSearch(mapping, formIn, request, response, errors);
        } catch (Exception e) {
            Logger.logExceptions(this, e);
        }
    }

    protected ActionForward processActionCancel(ActionMapping mapping, ActionForm formIn, HttpServletRequest request,
            HttpServletResponse response, ActionErrors errors) {

        ActionForward actionForward = null;
        HttpSession session = request.getSession(false);

        actionForward = mapping.findForward("reload");

        return actionForward;
    }
    
    protected ActionForward processActionClear(ActionMapping mapping, ActionForm formIn, HttpServletRequest request,
            HttpServletResponse response, ActionErrors errors) {

        ActionForward actionForward = null;
        HttpSession session = request.getSession(false);

        SimplePageEditStyleForm form = (SimplePageEditStyleForm) formIn;
        actionForward = new ActionForward(mapping.getInput());
        form.getMultiRows().clear();
        form.reset(mapping, request);
        form.setSidx(0);
        form.resetForm();

        return actionForward;
    }

    protected ActionForward processActionSave(ActionMapping mapping, ActionForm formIn, HttpServletRequest request,
            HttpServletResponse response, ActionErrors errors) {

        ActionForward actionForward = null;
        try {
            HttpSession session = request.getSession(false);
            SimplePageEditStyleForm form = (SimplePageEditStyleForm) formIn;
            actionForward = new ActionForward(mapping.getInput());
            User editingUser = (User) session.getAttribute(SimpleConstants.SESSION_USER);

            // validate form first
            beforeSave(mapping, formIn, request, response, errors);

            form.getFinalRows();
            form.validate(errors);
            form.moreValidate(mapping, formIn, request, response, errors);

            if (errors.size() == 0) {
                // todo: remember to add the form.setOldValues(object); where object is a collection of vos
                String formType = form.getFormType();
                if (SimpleConstants.FORM_TYPE_PAGE_EDIT.equals(formType)) { // new way
                    Collection collection = new ArrayList();
                    beforeFormToVos(mapping, form, request, response, errors, collection);
                    formToVos(form, collection);
                    afterFormToVos(mapping, form, request, response, errors, collection);
                    validateInputList(errors, collection);
                    if (errors.size() == 0) {
                        filterForEmptyInputList(collection, form, editingUser);
                        Collection originalCollection = (Collection) form.getOldValues();
                        filterForEditedList(collection, originalCollection, editingUser);
                        SimplePageEditStyleDelegate dg = getMasterDelegate(session);
                        dg.updateBatch(collection);
                        session.setAttribute(SimpleConstants.SESSION_ALERT_AFTER_SAVE, GENERIC_YES);
                        actionForward = mapping.findForward("reload");
                        form.setHasAddedRows(false);
                    }
                } else { // old way
                    SimpleBaseVo currentMasterVO = (SimpleBaseVo) getMasterVOClass().newInstance();
                    formToModel(form, currentMasterVO);
                    setSessionFields(request, currentMasterVO);
                    validateInput(errors, currentMasterVO);
                    filterForEmptyInput(currentMasterVO);
                    SimpleBaseVo originalMasterVO = (SimpleBaseVo) form.getOldValues();
                    currentMasterVO.setOldModel(originalMasterVO);
                    filterForEdited(currentMasterVO, originalMasterVO, editingUser);

                    if (currentMasterVO.checkFieldLength()) {
                        // not used anymore
                        // MasterDelegateInterface dg = (MasterDelegateInterface) getMasterDelegateInterfaceClass().newInstance();
                        SimplePageEditStyleDelegate dg = getMasterDelegate(session);
                        dg.updateMaster(currentMasterVO);
                        session.setAttribute(SimpleConstants.SESSION_ALERT_AFTER_SAVE, GENERIC_YES);
                        actionForward = mapping.findForward("reload");
                    }
                }
            }
            afterSave(mapping, formIn, request, response, errors);
        } catch (CheckFieldLengthException cfe) {
            Logger.logExceptions(this, cfe);
            errors.add(ActionErrors.GLOBAL_ERROR, new ActionError("error.msg", cfe.getMessage()));
        } catch (Exception e) {
            Logger.logExceptions(this, e);
            errors.add(ActionErrors.GLOBAL_ERROR, new ActionError("exception.general", e.getMessage()));
        }

        return actionForward;
    }

    protected ActionForward processActionRefresh(ActionMapping mapping, ActionForm formIn, HttpServletRequest request,
            HttpServletResponse response, ActionErrors errors) {

        ActionForward actionForward = null;
        try {
            beforeRefresh(mapping, formIn, request, response, errors);
            HttpSession session = request.getSession(false);
            SimplePageEditStyleForm form = (SimplePageEditStyleForm) formIn;
            actionForward = new ActionForward(mapping.getInput());
            int sidx = form.getSidx();
            processActionSearch(mapping, form, request, response, errors);
            form.setSidx(sidx);
            afterRefresh(mapping, formIn, request, response, errors);
        } catch (Exception e) {
            Logger.logExceptions(this, e);
            errors.add(ActionErrors.GLOBAL_ERROR, new ActionError("exception.general", e.getMessage()));
        }

        return actionForward;
    }

    protected SimplePageEditStyleDelegate getMasterDelegate(HttpSession session) {

        try {
            if (session.getAttribute(getMasterDelegateName()) != null) {
                return (SimplePageEditStyleDelegate) session.getAttribute(getMasterDelegateName());
            } else {
                SimplePageEditStyleDelegate dg = (SimplePageEditStyleDelegate) getMasterDelegateClass().newInstance();
                session.setAttribute(getMasterDelegateName(), dg);
                return dg;
            }
        } catch (Exception e) {
            Logger.logExceptions(this, e);
        }
        return null;
    }

    protected void removeMasterDelegate(HttpSession session) {

        try {
            getMasterDelegate(session).removeSessionBean();
            session.removeAttribute(getMasterDelegateName());
        } catch (Exception e) {
            Logger.logExceptions(this, e);
        }
    }

    // the old way
    /**
     * @ddeprecated
     */
    protected SimpleBaseVo searchByCriteria(SimplePageEditStyleDelegate dg, ActionForm form, HttpServletRequest request,
            Object criteria) {

        return dg.findMaster(criteria);
    }

    // the new way
    protected Collection findByCriteria(SimplePageEditStyleDelegate dg, ActionForm form, HttpServletRequest request,
            Object criteria) throws InstantiationException, IllegalAccessException, FindRecordException, java.rmi.RemoteException {

        Collection collection = dg.findByCriteria((SimplePageEditStyleVo) getMasterVOClass().newInstance(), criteria);
        return collection;
    }

    // the old way
    /**
     * @ddeprecated
     */
    public void modelToForm(SimpleBaseVo bizModel, SimplePageEditStyleForm form) {

        try {
            ChildList childList = bizModel.getChilds(getDetailVOClass());
            modelsToForm(childList, form);
        } catch (Exception e) {
            Logger.logExceptions(this, e);
        }
    }

    // the old way
    /**
     * @ddeprecated
     */
    public void modelsToForm(ChildList details, SimplePageEditStyleForm form) {

        try {
            for (int i = 0; i < details.size(); i++) {

                Object row = getDetailFormClass().newInstance();
                SimpleBaseVo bizModel = (SimpleBaseVo) details.get(i);

                CopyUtil.convToStrObj(row, bizModel);
                CopyUtil.copyByteArray(row, bizModel);
                if (bizModel.getIsDelete()) {
                    ((MultiRow) row).setIsDelete("checked");
                } else {
                    ((MultiRow) row).setIsDelete("");
                }

                if (bizModel.getIsExisting()) {
                    ((MultiRow) row).setModeModify();
                } else {
                    ((MultiRow) row).setModeCreate();
                }

                form.setRow(i, row);

            }

        } catch (Exception e) {
            Logger.logExceptions(this, e);
        }
    }

    // the new way
    public void voToForm(SimpleBaseVo model, MultiRow row) throws Exception {
        CopyUtil.convToStrObj(row, model);
        CopyUtil.copyByteArray(row, model);
        if (model.getIsDelete()) {
            row.setIsDelete("checked");
        } else {
            row.setIsDelete("");
        }

        if (model.getIsExisting()) {
            row.setModeModify();
        } else {
            row.setModeCreate();
        }
    }

    // the new way
    public void vosToForm(Collection collection, SimplePageEditStyleForm form) {
        try {
            int i = 0;
            SimplePageEditStyleVo firstVo = null;

            if (collection != null) {
                Iterator iterator = collection.iterator();
                while (iterator.hasNext()) {

                    MultiRow row = (MultiRow) getDetailFormClass().newInstance();
                    SimplePageEditStyleVo model = (SimplePageEditStyleVo) iterator.next();

                    if (i == 0) {
                        firstVo = model;
                        // save the first row's schema as the overall form's default,
                        // because all rows share the same table schema type
                        if (CommonUtil.isEmpty(firstVo) || CommonUtil.isEmpty(firstVo.getTableSchemaName())) {
                            form.setTs(new TableSchema());
                            form.setTsName("");
                        } else {
                            form.setTs((TableSchema) firstVo.getTableSchemaType().newInstance());
                            form.setTsName(firstVo.getTableSchemaName());
                        }
                    }

                    voToForm(model, row);

                    row.setTs(form.getTs());
                    row.setTsName(form.getTsName());

//                    if (model.getTableSchemaType() != null) {
//                        row.setTs((TableSchema) model.getTableSchemaType().newInstance());
//                    }
//                    if (model.getTableSchemaName() != null) {
//                        row.setTsName(model.getTableSchemaName());
//                    }

                    form.setRow(i++, row);
                }

            }
        } catch (Exception e) {
            Logger.logExceptions(this, e);
        }
    }

    // the old way
    /**
     * @ddeprecated
     */
    public void formToModel(SimplePageEditStyleForm form, SimpleBaseVo bizModel) {

        try {
            ChildList details = formToModels(form, bizModel);
            bizModel.storeChilds(details);
        } catch (Exception e) {
            Logger.logExceptions(this, e);
        }
    }

    // the old way
    /**
     * @ddeprecated
     */
    public ChildList formToModels(SimplePageEditStyleForm form, SimpleBaseVo parent) {

        ChildList details = null;
        try {
            int currIdx = form.getCurrIdx();
            ArrayList formRows = form.getMultiRows(currIdx);

            details = new ChildList(getDetailVOClass());

            boolean deleted, exist;

            for (int i = 0, rowIdx; i < formRows.size(); i++) {
                MultiRow formRow = (MultiRow) formRows.get(i);
                deleted = formRow.getIsDelete() != null && formRow.getIsDelete().length() > 0
                        && !formRow.getIsDelete().equals("");
                exist = formRow.getRowMode().equals(ROW_MODE_MODIFY);
                rowIdx = Integer.parseInt(formRow.getIdx());

                // if thing is undone... ignore this row
                if (!exist && deleted)
                    continue;

                // Insert if approriate
                SimpleBaseVo bizModel = (SimpleBaseVo) getDetailVOClass().newInstance();
                bizModel.setParent(parent);
                // Copy the Form Detail Data
                CopyUtil.cpNconv(bizModel, formRow);
                bizModel.setIsDelete(deleted);
                bizModel.setIsExisting(exist);
                details.add(bizModel);
            }
        } catch (Exception e) {
            Logger.logExceptions(this, e);
        }
        return details;
    }

    // the new way
    public void formToVos(SimplePageEditStyleForm form, Collection collection) {
        try {
            ArrayList rows = form.getMultiRows();

            Logger.debug(this, "formToVos(), Size of Final Rows = " + rows.size());

            boolean deleted, exist;

            for (int i = 0; i < rows.size(); i++) {
                MultiRow row = (MultiRow) rows.get(i);
                deleted = row.getIsDelete() != null && row.getIsDelete().length() > 0;
                exist = row.getRowMode().equals(ROW_MODE_MODIFY);

                // if thing is undone... ignore this row
                if (!exist && deleted)
                    continue;

                // Insert if approriate
                SimplePageEditStyleVo model = (SimplePageEditStyleVo) getMasterVOClass().newInstance();

                formToVo(row, model);

                collection.add(model);
            }
        } catch (Exception e) {
            Logger.logExceptions(this, e);
        }
    }

    // the new way
    public void formToVo(MultiRow row, SimplePageEditStyleVo model) throws Exception {

        boolean deleted = row.getIsDelete() != null && row.getIsDelete().length() > 0;
        boolean exist = row.getRowMode().equals(ROW_MODE_MODIFY);

        // Copy the Form Detail Data
        CopyUtil.cpNconv(model, row);

        model.setIsDelete(deleted);
        model.setIsExisting(exist);
    }

    // old way
    /**
     * @ddeprecated
     */
    protected void filterForEdited(SimpleBaseVo currentList, SimpleBaseVo originalList, User editingUser) throws Exception {

        try {
            ChildList childList = currentList.getChilds(getDetailVOClass());
            ChildList editedList = new ChildList(getDetailVOClass());
            SimpleBaseVo currentVO = null;
            SimpleBaseVo originalVO = null;
            Logger.debug(this, "filterForEdited(), Size of childList = " + childList.size());

            for (int i = 0; i < childList.size(); i++) {
                currentVO = (SimpleBaseVo) childList.get(i);

                if (currentVO == null) {
                    Logger.debug(this, "filterForEdited(), i=[" + i + "] why??? currentVO is null");
                    continue;
                }

                currentVO.setLastModifiedTime(currentVO.getUpdateDate());

                SimpleBasePk currentPK = (SimpleBasePk) currentVO.getPrimaryKey();

                if (originalList != null)
                    originalVO = originalList.getChildVO(currentPK, 0);
                if (originalVO != null)
                    originalVO.setLastModifiedTime(originalVO.getUpdateDate());
                if (originalVO == null || currentVO.getIsDelete() || !BeanUtil.isIdentical(originalVO, currentVO)) {

                    if (!currentVO.getIsExisting()) {
                        currentVO.setCreateUser(editingUser.getUserId());
                    } else {
                        currentVO.setUpdateUser(editingUser.getUserId());
                    }
                    editedList.add(currentVO);
                }
            }
            Logger.debug(this, "filterForEdited(), size of editedList = " + editedList.size());
            childList.clear();
            childList.addAll(editedList);
        } catch (Exception e) {
            Logger.logExceptions(this, e);
        }
    }

    protected final void filterForEditedList(Collection currentList, Collection originalList, User editingUser) throws Exception {
        if (currentList == null)
            return;

        HashMap originals = new HashMap();
        if (originalList != null) {
            Iterator iterator = originalList.iterator();
            while (iterator.hasNext()) {
                SimplePageEditStyleVo model = (SimplePageEditStyleVo) iterator.next();
                SimplePageEditStylePk pk = (SimplePageEditStylePk) model.getPrimaryKey();
                if (model != null)
                    model.setLastModifiedTime(model.getUpdateDate());
                originals.put(pk, model);
                
                Logger.debug("filterForEditedList(), original.getPrimaryKey()=" + pk);
                                
            }
        }

        Logger.debug(this, "filterForEditedList(), Size of childList = " + currentList.size());

        Iterator iterator = currentList.iterator();
        while (iterator.hasNext()) {
            SimplePageEditStyleVo currentVO = (SimplePageEditStyleVo) iterator.next();
            
            Logger.debug("filterForEditedList(), currentVO.getPrimaryKey()=" + currentVO.getPrimaryKey());
            
            SimplePageEditStyleVo originalVO = originals.containsKey(currentVO.getPrimaryKey()) ? (SimplePageEditStyleVo) originals
                    .get(currentVO.getPrimaryKey())
                    : null;

            try {
                if (currentVO != null)
                    currentVO.setLastModifiedTime(currentVO.getUpdateDate());
                
                boolean isIdentical = SimplePageEditStyleVo.isIdentical(originalVO, currentVO);

//                Logger.debug("filterForEditedList(), originalVO=null?" + (originalVO == null));
//                Logger.debug("filterForEditedList(), currentVO.getIsDelete()?" + (currentVO.getIsDelete()));
//                Logger.debug("filterForEditedList(), isIdentical=?" + (isIdentical));
                
                if (originalVO == null || currentVO.getIsDelete() || !isIdentical) {

                    if (!currentVO.getIsExisting()) {
                        currentVO.setCreateUser(editingUser.getUserId());
                    } else {
                        currentVO.setIsDirty(true);
                        currentVO.setUpdateUser(editingUser.getUserId());
                    }
                } else {
                    iterator.remove();
                }
            } catch (Exception e) {
                Logger.logExceptions(this, e);
            }
        }

        Logger.debug(this, "filterForEditedList(), Size of editedList = " + currentList.size());
    }

    protected void populateIsDelete(ActionForm formIn, HttpServletRequest request) {
        SimplePageEditStyleForm form = (SimplePageEditStyleForm) formIn;
        String[] isDelete = request.getParameterValues("isDelete");
        if (isDelete == null) {
            form.setIsDelete(isDelete);
        }
    }

    protected final void validateInputList(ActionErrors errors, Collection collection) throws Exception {
        if (collection == null) {
            return;
        }

        HashSet hs = new HashSet();
        boolean isNew = false;
        boolean isDelete = false;

        SimplePageEditStyleDelegate dg = new SimplePageEditStyleDelegate();

        Iterator iterator = collection.iterator();
        while (iterator.hasNext()) {
            SimplePageEditStyleVo model = (SimplePageEditStyleVo) iterator.next();
            SimplePageEditStylePk pk = (SimplePageEditStylePk) model.getPrimaryKey();

            if (pk != null) {

                isNew = !model.getIsExisting();
                isDelete = model.getIsDelete();

                if (!hs.contains(pk)) {
                    hs.add(pk);

                    SimpleBaseVo foundVo = dg.findByPrimaryKey(model, pk);
                    if (isNew && foundVo != null) {
                        errors.add(ActionErrors.GLOBAL_ERROR, new ActionError("error.general.key.duplicate", pk));
                    }
                } else {
                    errors.add(ActionErrors.GLOBAL_ERROR, new ActionError("error.general.key.duplicate", pk));
                }
            }
        }
    }

    protected void filterForEmptyInputList(Collection collection, SimplePageEditStyleForm form, User editingUser)
            throws Exception {
        if (collection == null)
            return;

        SimplePageEditStyleVo defaultModel = (SimplePageEditStyleVo) getInitialzedModel(form, editingUser);
        if (defaultModel == null) {
            MultiRow defaultRow = (MultiRow) getDetailFormClass().newInstance();
            defaultModel = (SimplePageEditStyleVo) getMasterVOClass().newInstance();
            formToVo(defaultRow, defaultModel);
        }

        Iterator iterator = collection.iterator();
        while (iterator.hasNext()) {
            SimplePageEditStyleVo model = (SimplePageEditStyleVo) iterator.next();
            if (SimplePageEditStyleVo.isIdentical(model, defaultModel)) {
                iterator.remove();
            }
        }

        Logger.debug(this, "filterForEmptyInputList(), Size of editedList = " + collection.size());
    }

    // //////////////////////////////////////////////////////////////////////////////
    // END OF LOGICAL AND BUSINESS METHODS
    // //////////////////////////////////////////////////////////////////////////////

    // ERP: not used anymore
    // protected Class getMasterDelegateInterfaceClass() {
    //
    // return MasterDelegateInterface.class;
    // }

    // protected String getMasterDelegateInterfaceName() {
    //
    // return "MASTER_DELEGATE_INTERFACE";
    // }

    // ERP Process: MasterDelegateInterface not used anymore
    // protected MasterDelegateInterface getMasterDelegateInterface(HttpSession session) {
    //
    // try {
    // if (session.getAttribute(getMasterDelegateInterfaceName()) != null) {
    // return (MasterDelegateInterface) session.getAttribute(getMasterDelegateInterfaceName());
    // } else {
    // MasterDelegateInterface dg = (MasterDelegateInterface) getMasterDelegateInterfaceClass().newInstance();
    // session.setAttribute(getMasterDelegateInterfaceName(), dg);
    // return dg;
    // }
    // } catch (Exception e) {
    // Logger.logExceptions(this, e);
    // }
    // return null;
    // }

    // ERP: not used anymore
    // protected BizModel searchByCriteria(MasterDelegateInterface dg, ActionForm form, HttpServletRequest request, Object
    // criteria) {
    //
    // return dg.findMaster(criteria);
    // }

    // public static final String SESSION_MASTER_DELEGATE = "MASTER_DELEGATE";

    // protected void setFormType(ActionMapping mapping, ActionForm formIn, HttpServletRequest request,
    // HttpServletResponse response, ActionErrors errors) {
    //
    // }

    // protected String getDetailFormSessionName() {
    //
    // return "detailForm";
    // }

    // protected Class getMasterFormClass() {
    //
    // return SimplePageEditStyleForm.class;
    // }

    // protected Class getMasterVOClass() {
    //
    // return SimpleBaseVo.class;
    // }

    // protected Class getDetailVOClass() {
    //
    // return SimpleBaseVo.class;
    // }

    // protected Class getDetailFormClass() {
    //
    // return MultiRow.class;
    // }

    // protected Class getSearchCriteriaClass() {
    //
    // return null;
    // }

    // protected void setOtherCriteria(ActionMapping mapping, ActionForm formIn, HttpServletRequest request,
    // HttpServletResponse response, ActionErrors errors, Object criteria) {
    //
    // }

}